package checkers3d.logic;

import java.util.LinkedList;
import java.util.Random;

/**
 * This class creates and randomly populates getPlayingSurface3D. The boards are
 * populated with Checkers, Kings, Kingifys, Mines, Safes, and Walls for both
 * players according to the setup rules within each class. All objects will have
 * the correct owner and render resource.
 *
 * @author Ruben Acuna
 */
public class GameSetupRandom
{
    /**
     * A random number generater to determine where to place pieces.
     */
    static private Random generator = new Random();

    /**
     * Creates a new PlayingSurface3D and inserts new pieces according to rules.
     *
     * @param home       The home player.
     * @param visitor    The visiting player.
     * @param boardSizeX The width of the board.
     * @param boardSizeY The height of the board.
     * @param boardSizeZ The number of boards.
     * @return A new PlayingSurface3D with pieces for both players.
     */
    static public PlayingSurface3D getPlayingSurface3D(Player home,
                                                       Player visitor,
                                                       int boardSizeX,
                                                       int boardSizeY,
                                                       int boardSizeZ,
                                                       boolean extendedPieces)
    {
        PlayingSurface3D playingSurface3D = new PlayingSurface3D(boardSizeX, boardSizeY, boardSizeZ);

        //1) add checkers
        insertBoardObjects(new BoardObjectChecker(home, home.getCheckerRR()), playingSurface3D, false);
        insertBoardObjects(new BoardObjectChecker(visitor, visitor.getCheckerRR()), playingSurface3D, true);
        
        //3) add kingifys for both players on all boards.
        insertBoardObjects(new BoardObjectKingify(visitor), playingSurface3D, false);
        insertBoardObjects(new BoardObjectKingify(home), playingSurface3D, true);
        
        if(extendedPieces)
        {
            //2) add kings
            insertBoardObjects(new BoardObjectKing(home, home.getKingRR()), playingSurface3D, false);
            insertBoardObjects(new BoardObjectKing(visitor, visitor.getKingRR()), playingSurface3D, true);

            //4) add mines
            insertBoardObjects(new BoardObjectMine(home, home.getMineRR()), playingSurface3D, false);
            insertBoardObjects(new BoardObjectMine(visitor, visitor.getMineRR()), playingSurface3D, true);

            //5) add safezones
            insertBoardObjects(new BoardObjectSafe(home, home.getSafeRR()), playingSurface3D, false);
            insertBoardObjects(new BoardObjectSafe(visitor, visitor.getSafeRR()), playingSurface3D, true);

            //6) add walls
            insertBoardObjects(new BoardObjectWall(home, home.getWallRR()), playingSurface3D, false);
            insertBoardObjects(new BoardObjectWall(visitor, visitor.getWallRR()), playingSurface3D, true);
        }

        return playingSurface3D;
    }

    /**
     * Inserts copies of an IBoardObject into a PlayingSurface3D according the
     * setup rules within each class. Builds a list of all valid setup locations
     * and random selects those locations and inserts a clone of the model
     * piece. Locations will only be black squares.
     *
     * @param modelPiece       A 'model' piece whose type we are inserting.
     * @param playingSurface3D The PlayingSurface3D we are inserting in.
     * @param oppositeSide     True if the player's pieces are suppose to be on
     *                         the top of the board.
     */
    private static void insertBoardObjects(IBoardObject modelPiece,
                                           PlayingSurface3D playingSurface3D,
                                           boolean oppositeSide)
    {
        LinkedList<Point3D> possibleLocations = new LinkedList<Point3D>();
        int boardSizeX = playingSurface3D.getSizeX();
        int boardSizeY = playingSurface3D.getSizeY();
        int boardSizeZ = playingSurface3D.getSizeZ();
        int placed = 0;

        //if we were setting up for the opposite side, flip the board so that
        //side is at the bottom.
        if(oppositeSide)
            playingSurface3D.flip();

        //probe all board locations for valid setup locations.
        for (int x = 0; x < boardSizeX; x = x + 2)
        {
            for (int y = 0; y < boardSizeY; y++)
            {
                for (int z = 0; z < boardSizeZ; z++)
                {
                    Point3D target = new Point3D(x, y, z);

                    if (y % 2 == 0)
                        target.x = target.x + 1;

                    if (modelPiece.isValidSetupPosition(playingSurface3D, target))
                        possibleLocations.add(target);
                }
            }
        }

        //randomly select locations and insert new pieces.
        while(!possibleLocations.isEmpty() &&
              placed != modelPiece.getSetupCount(boardSizeX, boardSizeY, boardSizeZ))
        {
            int randomIndex = generator.nextInt(possibleLocations.size());
            Point3D randomLocation = possibleLocations.get(randomIndex);

            playingSurface3D.addObject(modelPiece.clone(), randomLocation);
            possibleLocations.remove(randomLocation);

            placed++;
        }

        //if we were setting up for the opposite side, flip back.
        if(oppositeSide)
            playingSurface3D.flip();
    }
}
